-
Notifications
You must be signed in to change notification settings - Fork 8
Add Support Installation for Linux or Mac #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add 6 bash scripts for full Linux/macOS support - install-cliproxyapi.sh: Auto-detect OS/arch, install binary - start-cliproxyapi.sh: Server manager with PID tracking - cliproxyapi-oauth.sh: Interactive OAuth login - update-cliproxyapi.sh: Update from source or prebuilt - uninstall-cliproxyapi.sh: Clean removal - gui-cliproxyapi.sh: Web-based control panel - Update README.md and README_ID.md with Linux installation guide - Add testing instructions for verification - Update scripts/AGENTS.md with bash patterns and conventions
The official release uses 'cli-proxy-api-plus' as binary name, not 'cliproxyapi-plus'. Updated find command to check both names.
Signed-off-by: andikatuluspangestu <andhikatuluspangestu@gmail.com>
- Install GUI files to ~/.local/share/cliproxyapi/gui/ - Update gui-cliproxyapi script to use GUI_DIR instead of GUI_HTML - Auto-detect installed GUI location - Fallback to temporary minimal GUI if not found
Signed-off-by: andikatuluspangestu <andhikatuluspangestu@gmail.com>
Signed-off-by: andikatuluspangestu <andhikatuluspangestu@gmail.com>
Signed-off-by: andikatuluspangestu <andhikatuluspangestu@gmail.com>
WalkthroughThis pull request introduces comprehensive installation, update, and server management infrastructure through new Bash and Python scripts, alongside extensive documentation updates. The changes include an HTTP API server for GUI control, interactive OAuth CLI, GUI launcher, one-click installer, server manager, uninstall and update utilities, and expanded README documentation with quick-start guides and configuration examples. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant GUI as GUI Launcher<br/>(gui-cliproxyapi.sh)
participant Server as API Server<br/>(cliproxyapi-api-server.py)
participant Binary as CLIProxyAPI<br/>Binary
participant FS as Filesystem<br/>(config/logs)
User->>GUI: Run gui-cliproxyapi.sh [--port]
activate GUI
GUI->>GUI: Detect/generate GUI assets
GUI->>GUI: Validate port availability
GUI->>Server: Start API server (Python)
activate Server
Server->>FS: Read config.yaml
Server->>FS: Scan auth status
deactivate Server
GUI->>User: Open browser → http://localhost:port
deactivate GUI
User->>GUI: Click "Start Server" (via browser)
activate GUI
GUI->>Server: GET /api/start
activate Server
Server->>Binary: Execute start-cliproxyapi binary
activate Binary
Binary->>FS: Create PID file, write logs
Binary-->>Server: stdout (running state, endpoint)
deactivate Binary
Server->>FS: Parse output
Server->>User: JSON {status, pid, endpoint}
deactivate Server
deactivate GUI
User->>Server: GET /api/status
activate Server
Server->>Binary: Query process status
Server->>User: JSON {running, pid, endpoint}
deactivate Server
sequenceDiagram
participant User
participant Installer as install-cliproxyapi.sh
participant GH as GitHub API
participant FS as Filesystem
participant Binary as Binary/Config
User->>Installer: Run install-cliproxyapi.sh [--use-prebuilt]
activate Installer
Installer->>Installer: Detect OS & architecture
Installer->>Installer: Validate prerequisites (git, curl, Go)
alt Prebuilt Mode
Installer->>GH: Fetch latest release metadata
activate GH
GH-->>Installer: JSON {tag_name, assets[]}
deactivate GH
Installer->>GH: Download binary asset (OS/ARCH)
Installer->>FS: Extract & verify binary
else Source Build Mode
Installer->>FS: Clone or update repo
Installer->>Installer: Run go build
Installer->>FS: Place binary in target
end
Installer->>FS: Create config dirs (~/.cli-proxy-api, ~/.factory)
Installer->>FS: Generate config.yaml & config.json
Installer->>FS: Install binary to ~/.local/bin/cliproxyapi-plus
Installer->>FS: Copy helper scripts (oauth, start, update, uninstall, gui)
Installer->>FS: Copy Python API server script
Installer->>FS: Update shell RC with PATH entry
Installer->>User: Display installation summary & quick-start commands
deactivate Installer
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas requiring extra attention:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (10)
scripts/cliproxyapi-oauth.sh (4)
1-37: Binary/config path checks are sound; consider executable check for robustnessUsing
$HOME/.local/bin/cliproxyapi-plusand$HOME/.cli-proxy-api/config.yamlis consistent and the early‑exit checks avoid confusing downstream failures. If you want a bit more robustness, you could also assert that the binary is executable ([ -x "$BINARY_PATH" ]) rather than just present, but that’s optional for local installs.
38-86: DRY opportunity across provider‑specific login functionsAll
login_*functions follow the same pattern (log message → invoke binary with--configand a flag → success message). You could use a small helper likelogin_provider "Gemini" "--login"to reduce duplication and keep messages/flags in one place. This will make adding/removing providers less error‑prone, but the current code is functionally fine.
115-152: Interactive menu UX is straightforward; optional improvement on invalid choiceThe menu is clear and maps 1–9 directly to providers/all, with
0to exit. On invalid input you currently print an error and exit. If you want a smoother UX, you could loop until a valid choice is entered instead of exiting, but this is not required.
181-252: Argument parsing supports multiple providers; minor behavior notesThe argument loop correctly allows combining flags (e.g.
--gemini --copilot) and tracks whether any login was requested viaLOGIN_ANY. A couple of small notes:
LOGIN_ANYis treated as a string flag ("true"), which works but could also be written as a shell boolean idiom (LOGIN_ANY=0/1) if you prefer.- When using
--all, you’ll see both “All OAuth logins complete!” (fromlogin_all) and the final “OAuth login process complete!” banner — acceptable but a bit redundant.Functionally this is solid.
scripts/cliproxyapi-api-server.py (6)
61-142: Subprocess‑based server control is reasonable; consider narrowing exceptions and surfacing non‑200 statesThe
handle_status,handle_start,handle_stop, andhandle_restartmethods all usesubprocess.runwith explicit argument lists (noshell=True), timeouts, andcapture_output=True, which is good from a safety perspective and aligns with the static‑analysis concern about untrusted input (here the commands are fully under your control, so risk is low).A couple of improvements you might want to consider:
- Instead of
except Exception as e:everywhere, catch the specific failures you expect (e.g.,FileNotFoundError,subprocess.TimeoutExpired) and optionally log unexpected exceptions. This would address the BLE001 hints and make debugging easier.send_jsonalways responds with HTTP 200, even on clear failures (e.g., subprocess non‑zero or exceptions). If you start integrating with other tooling beyond your own GUI, you may want to allow passing an HTTP status code (e.g. 5xx on internal errors) to distinguish success from failure at the protocol level.Functionally this works, so these are more about robustness and observability.
246-261: Stats and update‑check stubs are fine; hard‑coded version should be kept in syncThe stubbed
/api/statsand/api/update/checkendpoints are fine for now and help stabilize the GUI. When you start wiring real data, consider:
- Avoid hard‑coding
"6.5.64"in two fields; instead, centralize it (env var, config, or module‑level constant) so it doesn’t get out of sync with the actual CLI version.- Returning
"available": Falseis OK as long as the GUI clearly communicates that updates are not yet implemented.No immediate issues.
263-279: Background update apply is straightforwardSpawning
update-cliproxyapiin the background viasubprocess.Popenwithoutshell=Trueis fine, and returning a confirmation JSON immediately matches the intended UX. Just be sure that the update script logs somewhere visible, since this endpoint won’t surface errors that occur after the process has started.
280-287:send_jsoncentralizes JSON output but always returns HTTP 200Centralizing JSON response headers and CORS handling in
send_jsonis good. The only downside is that you can’t currently distinguish success from failure at the HTTP level (everything is 200). If you later need richer error semantics, you might extendsend_jsonto accept an optionalstatusparameter and pass through non‑200 codes where appropriate.
288-291: Suppressing default logging reduces noise but may hide issuesOverriding
log_messagetopasskeeps the console clean, which is nice for end‑users. For debugging, you may eventually want a simple verbosity flag or environment check that conditionally enables logging instead of disabling it entirely.
226-245: Consider usingurllib.requestinstead ofcurlsubprocess for model discoveryThe current implementation using
subprocess.run()to callcurlworks correctly with proper error handling and JSON parsing fallback. However, sincecurlis only used here (not elsewhere in the codebase), switching tourllib.requestorhttp.clientwould eliminate the external runtime dependency and simplify the code without any functional loss. This is a straightforward refactoring opportunity if you want to reduce deployment requirements.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
README.md(9 hunks)README_ID.md(8 hunks)scripts/AGENTS.md(7 hunks)scripts/cliproxyapi-api-server.py(1 hunks)scripts/cliproxyapi-oauth.sh(1 hunks)scripts/gui-cliproxyapi.sh(1 hunks)scripts/install-cliproxyapi.sh(1 hunks)scripts/start-cliproxyapi.sh(1 hunks)scripts/uninstall-cliproxyapi.sh(1 hunks)scripts/update-cliproxyapi.sh(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
scripts/uninstall-cliproxyapi.sh (5)
scripts/install-cliproxyapi.sh (3)
echo_warning(48-48)echo_step(46-46)echo_success(47-47)scripts/gui-cliproxyapi.sh (3)
echo_warning(59-59)echo_info(57-57)echo_success(58-58)scripts/update-cliproxyapi.sh (3)
echo_warning(37-37)echo_step(35-35)echo_success(36-36)scripts/cliproxyapi-oauth.sh (3)
echo_warning(22-22)echo_info(20-20)echo_success(21-21)scripts/start-cliproxyapi.sh (3)
echo_warning(23-23)echo_info(21-21)echo_success(22-22)
scripts/cliproxyapi-api-server.py (1)
scripts/start-cliproxyapi.sh (1)
is_running(27-38)
🪛 Ruff (0.14.8)
scripts/cliproxyapi-api-server.py
64-64: subprocess call: check for execution of untrusted input
(S603)
86-86: Do not catch blind exception: Exception
(BLE001)
92-92: subprocess call: check for execution of untrusted input
(S603)
104-104: Do not catch blind exception: Exception
(BLE001)
110-110: subprocess call: check for execution of untrusted input
(S603)
122-122: Do not catch blind exception: Exception
(BLE001)
128-128: subprocess call: check for execution of untrusted input
(S603)
140-140: Do not catch blind exception: Exception
(BLE001)
163-163: subprocess call: check for execution of untrusted input
(S603)
173-173: Do not catch blind exception: Exception
(BLE001)
185-185: Do not catch blind exception: Exception
(BLE001)
223-223: Do not catch blind exception: Exception
(BLE001)
223-223: Local variable e is assigned to but never used
Remove assignment to unused variable e
(F841)
230-231: Starting a process with a partial executable path
(S607)
243-243: Do not catch blind exception: Exception
(BLE001)
267-267: subprocess call: check for execution of untrusted input
(S603)
277-277: Do not catch blind exception: Exception
(BLE001)
🪛 Shellcheck (0.11.0)
scripts/update-cliproxyapi.sh
[warning] 9-9: REPO_URL appears unused. Verify use (or export if used externally).
(SC2034)
scripts/gui-cliproxyapi.sh
[warning] 54-54: MAGENTA appears unused. Verify use (or export if used externally).
(SC2034)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: Agent
🔇 Additional comments (20)
README_ID.md (1)
120-160: Quick Start (Linux/macOS) section is well-documented.The section provides clear installation paths, prerequisites, and post-installation steps aligned with the actual script implementations. Instructions for reloading shell config and using
--use-prebuiltflag match the installer script behavior.README.md (1)
120-168: Linux/macOS Quick Start documentation is comprehensive.Provides clear one-click setup path and step-by-step post-installation instructions. Documentation aligns with actual script capabilities (--use-prebuilt, --background, etc.).
scripts/uninstall-cliproxyapi.sh (3)
1-46: Solid script header and initialization.Proper shebang, argument parsing, error handling setup, and colored output functions. Structure follows best practices for Bash uninstall scripts.
80-123: File removal logic is well-structured and safe.Proper existence checks, conditional removal based on flags, and sensible defaults (preserving auth tokens unless --all is used). Follows uninstall best practices.
125-164: Thoughtful PATH cleanup guidance and final status reporting.Script appropriately detects shell configuration files and guides users to manually remove PATH entries, reducing risk of accidental corruption. Final summary clearly indicates what was/wasn't removed.
scripts/update-cliproxyapi.sh (1)
1-70: Update script header and initialization look solid.Good OS/ARCH detection matching install script, version checking, and proper prerequisites validation. Architecture handling is consistent with rest of codebase.
scripts/start-cliproxyapi.sh (2)
1-38: Well-structured server manager with clear function organization.Proper initialization, color definitions, and output functions. Script sets up all necessary paths and variables for server lifecycle management.
26-107: Solid process management with appropriate signal handling.
is_running()properly validates processes,start_server()correctly uses nohup for background execution, andstop_server()implements sensible graceful-shutdown-then-force pattern. Error handling at each step is appropriate.scripts/install-cliproxyapi.sh (6)
1-70: Excellent installer structure with comprehensive system detection.Proper header, variable initialization, argument parsing, and OS/ARCH detection matching other scripts. Foundation for the installation process is solid.
162-184: Source build path assumes specific project structure.Line 179 runs
go build -o ... ./cmd/serverwithout verifying this path exists in the cloned repository. If CLIProxyAPIPlus uses a different build path, this will fail with unclear error messaging.Consider adding a validation check:
if [ ! -f "$CLONE_DIR/cmd/server/main.go" ]; then echo_error "Expected build path ./cmd/server not found in cloned repo" exit 1 fiHowever, this may be acceptable if CLIProxyAPIPlus' structure is stable. Document the assumption in a comment if intentional.
186-241: Config generation is well-structured with sensible defaults.Both
config.yamland.factory/config.jsonare properly generated with appropriate defaults. Droid models list (18 entries) comprehensively covers all supported providers. JSON formatting is valid.
253-275: Smart PATH configuration with duplicate prevention.Shell RC detection is robust (bash/zsh/profile fallback), duplicate checks prevent multiple PATH entries, and the script informs users when a shell restart is needed. Follows best practices for shell configuration.
277-306: Helper script installation is thoughtful but could verify source existence.The script copies helper scripts with proper executable permissions and removes
.shextension for clean command names. However, it silently skips missing scripts (line 282 checksif [ -f "$SCRIPT_DIR/$script" ]). Consider whether silent skipping is acceptable or if missing scripts should trigger a warning.
46-61: Missingecho_info()function definition.Line 61 calls
echo_info()but the script only definesecho_step(),echo_success(),echo_warning(), andecho_error()at lines 46-49.Add the missing function:
echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } echo_success() { echo -e "${GREEN}[+] $1${NC}"; } echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; } echo_error() { echo -e "${RED}[-] $1${NC}"; } +echo_info() { echo -e "${CYAN}[*] $1${NC}"; }Likely an incorrect or invalid review comment.
scripts/AGENTS.md (1)
35-38: The review comment is based on incorrect information and does not apply to this repository.The repository contains only PowerShell scripts (.ps1), not Bash scripts (.sh). AGENTS.md is a 154-line PowerShell documentation file with no Bash section. The referenced scripts
gui-cliproxyapi.shandinstall-cliproxyapi.shdo not exist; the actual scripts aregui-cliproxyapi.ps1andinstall-cliproxyapi.ps1. The functions mentioned (echo_info(),echo_step()) are Bash naming conventions that do not appear in this codebase. The actual scripts use PowerShell'sWrite-Step,Write-Success,Write-Warning, andWrite-Errorfunctions, which are correctly documented in AGENTS.md lines 49-52. There are no non-existent lines 178-190 to update, and no inconsistency exists between documentation and implementation.Likely an incorrect or invalid review comment.
scripts/cliproxyapi-oauth.sh (2)
87-113:login_allflow is clear and respects failures without abortingThe combined login flow with a confirmation prompt and per‑provider error handling (
${FUNCS[$i]} || echo_warning ...) works well, especially combined withset -e(which is correctly suppressed by the||guard here). This looks good and should behave as users expect when some providers fail.
154-179: Help text matches implemented optionsThe
show_helpoutput correctly documents all supported flags and examples, including multi‑provider usage. Keeping this in sync with the argument parser will be important as you add/remove providers, but it’s consistent right now.scripts/cliproxyapi-api-server.py (3)
20-60: Routing structure is clear and maintainableThe separation of GET and POST routes with dedicated handler methods keeps the surface area understandable. Using
/api/...and delegating everything else tosuper().do_GET()for static GUI files is a clean pattern and should be easy to extend as you add new endpoints.
143-175: OAuth endpoint mapping is safe but depends on stable provider namesThe
/api/oauth/{provider}handler uses a fixedprovider_mapand only invokescliproxyapi-oauthwhen the provider is recognized, so the S603 static warning about untrusted subprocess input is effectively mitigated here. Just be aware that the external URL schema and GUI must stay aligned with these keys (gemini,antigravity, etc.), or you’ll hit the “Unknown provider” path.No further changes required from a correctness or security angle in this method.
176-187: Config endpoint is simple and robust for missing filesReading
config.yamlfromCONFIG_DIRand returning an empty string when it doesn’t exist is straightforward. Wrapping file access intry/exceptand returning an error field on exception is a good pattern for the GUI to consume.
| def handle_auth_status(self): | ||
| """Get auth status for providers""" | ||
| try: | ||
| auth_files = list(CONFIG_DIR.glob("*.json")) | ||
| providers = { | ||
| "gemini": False, | ||
| "antigravity": False, | ||
| "copilot": False, | ||
| "codex": False, | ||
| "claude": False, | ||
| "qwen": False, | ||
| "iflow": False, | ||
| "kiro": False | ||
| } | ||
|
|
||
| for f in auth_files: | ||
| name = f.stem.lower() | ||
| if "gemini" in name or "@gmail.com" in name: | ||
| providers["gemini"] = True | ||
| if "antigravity" in name: | ||
| providers["antigravity"] = True | ||
| if "copilot" in name or "github" in name: | ||
| providers["copilot"] = True | ||
| if "codex" in name: | ||
| providers["codex"] = True | ||
| if "claude" in name: | ||
| providers["claude"] = True | ||
| if "qwen" in name: | ||
| providers["qwen"] = True | ||
| if "iflow" in name: | ||
| providers["iflow"] = True | ||
| if "kiro" in name: | ||
| providers["kiro"] = True | ||
|
|
||
| self.send_json(providers) | ||
| except Exception as e: | ||
| self.send_json({p: False for p in ["gemini", "antigravity", "copilot", "codex", "claude", "qwen", "iflow", "kiro"]}) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auth status detection works; fix unused exception variable and consider future‑proofing naming heuristics
The heuristic over *.json files in CONFIG_DIR to infer provider auth state is a practical solution and should work fine with your current naming conventions.
Two small issues:
- In the
exceptblock you useexcept Exception as e:but never referencee. This is what Ruff flagged (F841). Either drop theas eor log the exception somewhere. - The string‑matching heuristics (
"gemini" in name or "@gmail.com" in name,"copilot" in name or "github" in name, etc.) are tightly coupled to current filenames. If you change how auth artifacts are named, it would be easy to drift. Not urgent, but eventually a small metadata file listing authenticated providers would be more robust.
Proposed minimal fix for the unused variable:
- except Exception as e:
- self.send_json({p: False for p in ["gemini", "antigravity", "copilot", "codex", "claude", "qwen", "iflow", "kiro"]})
+ except Exception:
+ self.send_json({p: False for p in ["gemini", "antigravity", "copilot", "codex", "claude", "qwen", "iflow", "kiro"]})🧰 Tools
🪛 Ruff (0.14.8)
223-223: Do not catch blind exception: Exception
(BLE001)
223-223: Local variable e is assigned to but never used
Remove assignment to unused variable e
(F841)
🤖 Prompt for AI Agents
In scripts/cliproxyapi-api-server.py around lines 188 to 225, the except block
declares an unused exception variable ("except Exception as e:") which triggers
a linter warning; change it to "except Exception:" (or log the exception via
process logger) and keep the fallback JSON response as-is; optionally consider
replacing the filename-heuristic with a small metadata file for provider auth
detection in future to avoid brittle name matching.
| def main(): | ||
| """Start the API server""" | ||
| # Change to GUI directory | ||
| gui_dir = HOME / ".local" / "share" / "cliproxyapi" / "gui" | ||
| if gui_dir.exists(): | ||
| os.chdir(gui_dir) | ||
|
|
||
| with socketserver.TCPServer(("", PORT), APIHandler) as httpd: | ||
| print(f"API Server running on http://localhost:{PORT}") | ||
| print(f"GUI available at http://localhost:{PORT}") | ||
| print("Press Ctrl+C to stop") | ||
| try: | ||
| httpd.serve_forever() | ||
| except KeyboardInterrupt: | ||
| print("\nShutting down...") | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bind server to localhost only to avoid exposing control API on the network
Right now you instantiate the server as:
with socketserver.TCPServer(("", PORT), APIHandler) as httpd:Passing "" binds to all interfaces (0.0.0.0), which exposes this management API — including start/stop, OAuth triggering, config access, and update commands — on any reachable network interface. Given this is a local control plane for a desktop tool, that’s a security risk and unnecessary.
You almost certainly want to bind only to the loopback interface so it’s only accessible from the local machine:
- with socketserver.TCPServer(("", PORT), APIHandler) as httpd:
+ with socketserver.TCPServer(("127.0.0.1", PORT), APIHandler) as httpd:This still works seamlessly with the bundled GUI (which talks to localhost) but prevents other machines on the network from hitting these endpoints directly.
🤖 Prompt for AI Agents
In scripts/cliproxyapi-api-server.py around lines 292 to 307, the server is
currently bound to all interfaces via socketserver.TCPServer(("", PORT),
APIHandler) which exposes the control API on the network; change the bind
address to the loopback (e.g., "127.0.0.1" or "localhost") so the TCPServer
listens only on localhost (socketserver.TCPServer(("127.0.0.1", PORT),
APIHandler)), keeping the GUI functional while preventing remote access.
| # Colors | ||
| GREEN='\033[0;32m' | ||
| CYAN='\033[0;36m' | ||
| YELLOW='\033[1;33m' | ||
| RED='\033[0;31m' | ||
| MAGENTA='\033[0;35m' | ||
| NC='\033[0m' | ||
|
|
||
| echo_info() { echo -e "${CYAN}[*] $1${NC}"; } | ||
| echo_success() { echo -e "${GREEN}[+] $1${NC}"; } | ||
| echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; } | ||
| echo_error() { echo -e "${RED}[-] $1${NC}"; } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused color variable MAGENTA.
The MAGENTA variable is defined at line 54 but never used in the script. The color initialization includes MAGENTA but only GREEN, CYAN, YELLOW, RED, and NC are actually used.
Either remove the unused variable or apply it to the banner output for consistency with other scripts.
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 54-54: MAGENTA appears unused. Verify use (or export if used externally).
(SC2034)
🤖 Prompt for AI Agents
In scripts/gui-cliproxyapi.sh around lines 49 to 61, the MAGENTA color variable
is defined but never used; remove the unused MAGENTA assignment or apply it to
an appropriate output (for example the banner) to keep color definitions
consistent. If removing, delete the MAGENTA line; if applying, change one echo
that should stand out (e.g., banner or header) to use ${MAGENTA}...${NC} and
ensure the echo function or literal uses -e so escape codes render correctly.
| # Start server with API backend | ||
| API_SERVER="$HOME/.local/bin/cliproxyapi-api-server" | ||
| if command -v python3 &> /dev/null; then | ||
| if [ -f "$API_SERVER" ]; then | ||
| # Use Python API server with management endpoints | ||
| python3 "$API_SERVER" 2>/dev/null | ||
| else | ||
| # Fallback to simple HTTP server | ||
| cd "$GUI_DIR" | ||
| python3 -m http.server "$GUI_PORT" 2>/dev/null | ||
| fi | ||
| elif command -v python &> /dev/null; then | ||
| cd "$GUI_DIR" | ||
| python -m SimpleHTTPServer "$GUI_PORT" 2>/dev/null | ||
| else | ||
| echo_error "No HTTP server available (python/python3 required)" | ||
| echo_info "Please install Python to use the GUI" | ||
| exit 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTTP server startup logic could fail silently on Python API server.
The script attempts to start the API server (line 190) without verifying it's executable or properly handling stderr. If python3 "$API_SERVER" fails to start or exits, the fallback HTTP server won't start because the first command terminates the script execution (due to set -e at line 7).
Apply this fix to ensure fallback works:
API_SERVER="$HOME/.local/bin/cliproxyapi-api-server"
if command -v python3 &> /dev/null; then
if [ -f "$API_SERVER" ]; then
- # Use Python API server with management endpoints
- python3 "$API_SERVER" 2>/dev/null
+ # Use Python API server with management endpoints
+ python3 "$API_SERVER" 2>/dev/null || cd "$GUI_DIR" && python3 -m http.server "$GUI_PORT" 2>/dev/null
else
# Fallback to simple HTTP server
cd "$GUI_DIR"
python3 -m http.server "$GUI_PORT" 2>/dev/null
fi
elif command -v python &> /dev/null; then
cd "$GUI_DIR"
python -m SimpleHTTPServer "$GUI_PORT" 2>/dev/null
else
echo_error "No HTTP server available (python/python3 required)"
echo_info "Please install Python to use the GUI"
exit 1
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Start server with API backend | |
| API_SERVER="$HOME/.local/bin/cliproxyapi-api-server" | |
| if command -v python3 &> /dev/null; then | |
| if [ -f "$API_SERVER" ]; then | |
| # Use Python API server with management endpoints | |
| python3 "$API_SERVER" 2>/dev/null | |
| else | |
| # Fallback to simple HTTP server | |
| cd "$GUI_DIR" | |
| python3 -m http.server "$GUI_PORT" 2>/dev/null | |
| fi | |
| elif command -v python &> /dev/null; then | |
| cd "$GUI_DIR" | |
| python -m SimpleHTTPServer "$GUI_PORT" 2>/dev/null | |
| else | |
| echo_error "No HTTP server available (python/python3 required)" | |
| echo_info "Please install Python to use the GUI" | |
| exit 1 | |
| # Start server with API backend | |
| API_SERVER="$HOME/.local/bin/cliproxyapi-api-server" | |
| if command -v python3 &> /dev/null; then | |
| if [ -f "$API_SERVER" ]; then | |
| # Use Python API server with management endpoints | |
| python3 "$API_SERVER" 2>/dev/null || cd "$GUI_DIR" && python3 -m http.server "$GUI_PORT" 2>/dev/null | |
| else | |
| # Fallback to simple HTTP server | |
| cd "$GUI_DIR" | |
| python3 -m http.server "$GUI_PORT" 2>/dev/null | |
| fi | |
| elif command -v python &> /dev/null; then | |
| cd "$GUI_DIR" | |
| python -m SimpleHTTPServer "$GUI_PORT" 2>/dev/null | |
| else | |
| echo_error "No HTTP server available (python/python3 required)" | |
| echo_info "Please install Python to use the GUI" | |
| exit 1 |
| # Confirmation prompt | ||
| if [ "$FORCE" = false ]; then | ||
| echo_warning "This will remove CLIProxyAPI-Plus from your system." | ||
| if [ "$REMOVE_ALL" = true ]; then | ||
| echo_warning "Including auth tokens and configuration files!" | ||
| else | ||
| echo_info "Auth tokens will be preserved (use --all to remove them)" | ||
| fi | ||
| echo "" | ||
| read -p "Continue? [y/N] " -n 1 -r | ||
| echo | ||
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| echo_info "Uninstall cancelled" | ||
| exit 0 | ||
| fi | ||
| fi | ||
|
|
||
| # Stop server if running | ||
| PID_FILE="$CONFIG_DIR/server.pid" | ||
| if [ -f "$PID_FILE" ]; then | ||
| PID=$(cat "$PID_FILE") | ||
| if ps -p "$PID" > /dev/null 2>&1; then | ||
| echo_step "Stopping server..." | ||
| kill "$PID" 2>/dev/null || true | ||
| sleep 1 | ||
| if ps -p "$PID" > /dev/null 2>&1; then | ||
| kill -9 "$PID" 2>/dev/null || true | ||
| fi | ||
| echo_success "Server stopped" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined function reference in confirmation prompt.
Line 54 calls echo_info() but this function is not defined in the script. The script defines echo_step(), echo_success(), echo_warning(), and echo_error() at lines 35-38, but not echo_info().
Apply this fix:
echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; }
echo_success() { echo -e "${GREEN}[+] $1${NC}"; }
echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; }
echo_error() { echo -e "${RED}[-] $1${NC}"; }
+echo_info() { echo -e "${CYAN}[*] $1${NC}"; }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In scripts/uninstall-cliproxyapi.sh around lines 48 to 78, the script calls the
undefined function echo_info at two places (the preservation message and
"Uninstall cancelled"); replace those echo_info calls with the existing
echo_step function (or implement a short echo_info wrapper that delegates to
echo_step) so the informational messages use a defined logger and the script no
longer references an undefined function.
| REPO_URL="https://github.com/router-for-me/CLIProxyAPIPlus.git" | ||
| RELEASE_API="https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest" | ||
| CLONE_DIR="$HOME/CLIProxyAPIPlus" | ||
| BIN_DIR="$HOME/.local/bin" | ||
| BINARY_NAME="cliproxyapi-plus" | ||
|
|
||
| USE_PREBUILT=false | ||
| FORCE=false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused REPO_URL variable.
Line 9 defines REPO_URL="https://github.com/..." but it's never used in the script. The update logic uses RELEASE_API (line 10) for prebuilt downloads, or pulls from existing CLONE_DIR (line 11) for source updates.
Apply this fix to remove dead code:
-REPO_URL="https://github.com/router-for-me/CLIProxyAPIPlus.git"
RELEASE_API="https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| REPO_URL="https://github.com/router-for-me/CLIProxyAPIPlus.git" | |
| RELEASE_API="https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest" | |
| CLONE_DIR="$HOME/CLIProxyAPIPlus" | |
| BIN_DIR="$HOME/.local/bin" | |
| BINARY_NAME="cliproxyapi-plus" | |
| USE_PREBUILT=false | |
| FORCE=false | |
| RELEASE_API="https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest" | |
| CLONE_DIR="$HOME/CLIProxyAPIPlus" | |
| BIN_DIR="$HOME/.local/bin" | |
| BINARY_NAME="cliproxyapi-plus" | |
| USE_PREBUILT=false | |
| FORCE=false |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 9-9: REPO_URL appears unused. Verify use (or export if used externally).
(SC2034)
🤖 Prompt for AI Agents
In scripts/update-cliproxyapi.sh around lines 9 to 16, the REPO_URL variable is
defined but never used; remove the unused REPO_URL declaration and any
references to it (if present elsewhere) so the script only defines and uses
RELEASE_API, CLONE_DIR, BIN_DIR, BINARY_NAME, USE_PREBUILT, and FORCE; run a
quick grep to confirm REPO_URL is not referenced elsewhere and update comments
or docs if they mention the removed variable.
| # Check if currently installed | ||
| if [ ! -f "$BIN_DIR/$BINARY_NAME" ]; then | ||
| echo_error "CLIProxyAPI-Plus is not installed" | ||
| echo_info "Run install-cliproxyapi first" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Get current version | ||
| CURRENT_VERSION="unknown" | ||
| if [ -f "$BIN_DIR/$BINARY_NAME" ]; then | ||
| CURRENT_VERSION=$("$BIN_DIR/$BINARY_NAME" --version 2>&1 | head -1 || echo "unknown") | ||
| fi | ||
| echo_info "Current version: $CURRENT_VERSION" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined echo_info() function usage.
Lines 61 and 70 call echo_info() which is not defined. The script only defines echo_step(), echo_success(), echo_warning(), and echo_error() at lines 35-38.
Add the missing function definition:
echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; }
echo_success() { echo -e "${GREEN}[+] $1${NC}"; }
echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; }
echo_error() { echo -e "${RED}[-] $1${NC}"; }
+echo_info() { echo -e "${CYAN}[*] $1${NC}"; }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In scripts/update-cliproxyapi.sh around lines 58 to 70 the script calls
echo_info() but that helper is not defined (only
echo_step/echo_success/echo_warning/echo_error exist); add a new echo_info
function consistent with the other helpers (print to stdout with the same
prefix/format as the other echo_* functions) near the existing helper
definitions (around lines 35-38) so calls to echo_info succeed and formatting
remains consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7 issues found across 10 files
Prompt for AI agents (all 7 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="scripts/install-cliproxyapi.sh">
<violation number="1" location="scripts/install-cliproxyapi.sh:256">
P2: Shell detection logic is flawed - `$BASH_VERSION` is always set because this script runs under bash (shebang `#!/usr/bin/env bash`). This means zsh users will incorrectly have PATH added to `.bashrc` instead of `.zshrc`. Use `$SHELL` environment variable to detect the user's actual login shell instead.</violation>
</file>
<file name="scripts/AGENTS.md">
<violation number="1" location="scripts/AGENTS.md:234">
P2: This shell detection logic will always detect bash because `$BASH_VERSION` is set by the bash interpreter running the script, not by the user's login shell. Use `$SHELL` instead to correctly detect the user's shell config file.
Example fix:
```bash
case "$SHELL" in
*/bash) SHELL_RC="$HOME/.bashrc" ;;
*/zsh) SHELL_RC="$HOME/.zshrc" ;;
*) SHELL_RC="$HOME/.profile" ;;
esac
```</violation>
</file>
<file name="scripts/start-cliproxyapi.sh">
<violation number="1" location="scripts/start-cliproxyapi.sh:33">
P2: Logic bug: `is_running` check after removing PID file will always return false. The `rm -f "$PID_FILE"` on line 97 removes the file that `is_running()` depends on, so the subsequent check can never detect if the process failed to stop. Move the PID file removal after the final verification, or check the process directly using the stored `$PID` variable.</violation>
</file>
<file name="scripts/gui-cliproxyapi.sh">
<violation number="1" location="scripts/gui-cliproxyapi.sh:190">
P2: The GUI_PORT variable is not passed to the API server, so the `--port` option is ignored. The API server will always run on its hardcoded port 8318.</violation>
</file>
<file name="scripts/uninstall-cliproxyapi.sh">
<violation number="1" location="scripts/uninstall-cliproxyapi.sh:54">
P1: `echo_info` function is used but never defined. The script will fail at runtime because `set -e` is enabled. Add the missing function definition alongside the other echo helpers.</violation>
</file>
<file name="scripts/update-cliproxyapi.sh">
<violation number="1" location="scripts/update-cliproxyapi.sh:38">
P0: Function `echo_info` is used but never defined. This will cause the script to fail at runtime with 'command not found'. Add the missing function definition alongside the other echo helper functions.</violation>
</file>
<file name="scripts/cliproxyapi-api-server.py">
<violation number="1" location="scripts/cliproxyapi-api-server.py:299">
P1: Server binds to all network interfaces instead of localhost only. This exposes the management API to the entire network, allowing remote control of server start/stop, OAuth, and updates. For a local management API, bind to `127.0.0.1` instead.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| # Add ~/.local/bin to PATH if not already | ||
| echo_step "Configuring PATH..." | ||
| SHELL_RC="" | ||
| if [ -n "$BASH_VERSION" ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Shell detection logic is flawed - $BASH_VERSION is always set because this script runs under bash (shebang #!/usr/bin/env bash). This means zsh users will incorrectly have PATH added to .bashrc instead of .zshrc. Use $SHELL environment variable to detect the user's actual login shell instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/install-cliproxyapi.sh, line 256:
<comment>Shell detection logic is flawed - `$BASH_VERSION` is always set because this script runs under bash (shebang `#!/usr/bin/env bash`). This means zsh users will incorrectly have PATH added to `.bashrc` instead of `.zshrc`. Use `$SHELL` environment variable to detect the user's actual login shell instead.</comment>
<file context>
@@ -0,0 +1,389 @@
+# Add ~/.local/bin to PATH if not already
+echo_step "Configuring PATH..."
+SHELL_RC=""
+if [ -n "$BASH_VERSION" ]; then
+ SHELL_RC="$HOME/.bashrc"
+elif [ -n "$ZSH_VERSION" ]; then
</file context>
| if [ -n "$BASH_VERSION" ]; then | ||
| SHELL_RC="$HOME/.bashrc" | ||
| elif [ -n "$ZSH_VERSION" ]; then | ||
| SHELL_RC="$HOME/.zshrc" | ||
| else | ||
| SHELL_RC="$HOME/.profile" | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This shell detection logic will always detect bash because $BASH_VERSION is set by the bash interpreter running the script, not by the user's login shell. Use $SHELL instead to correctly detect the user's shell config file.
Example fix:
case "$SHELL" in
*/bash) SHELL_RC="$HOME/.bashrc" ;;
*/zsh) SHELL_RC="$HOME/.zshrc" ;;
*) SHELL_RC="$HOME/.profile" ;;
esacPrompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/AGENTS.md, line 234:
<comment>This shell detection logic will always detect bash because `$BASH_VERSION` is set by the bash interpreter running the script, not by the user's login shell. Use `$SHELL` instead to correctly detect the user's shell config file.
Example fix:
```bash
case "$SHELL" in
*/bash) SHELL_RC="$HOME/.bashrc" ;;
*/zsh) SHELL_RC="$HOME/.zshrc" ;;
*) SHELL_RC="$HOME/.profile" ;;
esac
```</comment>
<file context>
@@ -117,8 +143,118 @@ Select-String -Path "scripts\NEW_SCRIPT.ps1" -Pattern "ErrorActionPreference" #
+esac
+
+# Detect shell config file
+if [ -n "$BASH_VERSION" ]; then
+ SHELL_RC="$HOME/.bashrc"
+elif [ -n "$ZSH_VERSION" ]; then
</file context>
| if [ -n "$BASH_VERSION" ]; then | |
| SHELL_RC="$HOME/.bashrc" | |
| elif [ -n "$ZSH_VERSION" ]; then | |
| SHELL_RC="$HOME/.zshrc" | |
| else | |
| SHELL_RC="$HOME/.profile" | |
| fi | |
| case "$SHELL" in | |
| */bash) SHELL_RC="$HOME/.bashrc" ;; | |
| */zsh) SHELL_RC="$HOME/.zshrc" ;; | |
| *) SHELL_RC="$HOME/.profile" ;; | |
| esac |
| if ps -p "$PID" > /dev/null 2>&1; then | ||
| return 0 | ||
| else | ||
| rm -f "$PID_FILE" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Logic bug: is_running check after removing PID file will always return false. The rm -f "$PID_FILE" on line 97 removes the file that is_running() depends on, so the subsequent check can never detect if the process failed to stop. Move the PID file removal after the final verification, or check the process directly using the stored $PID variable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/start-cliproxyapi.sh, line 33:
<comment>Logic bug: `is_running` check after removing PID file will always return false. The `rm -f "$PID_FILE"` on line 97 removes the file that `is_running()` depends on, so the subsequent check can never detect if the process failed to stop. Move the PID file removal after the final verification, or check the process directly using the stored `$PID` variable.</comment>
<file context>
@@ -0,0 +1,207 @@
+ if ps -p "$PID" > /dev/null 2>&1; then
+ return 0
+ else
+ rm -f "$PID_FILE"
+ return 1
+ fi
</file context>
| if command -v python3 &> /dev/null; then | ||
| if [ -f "$API_SERVER" ]; then | ||
| # Use Python API server with management endpoints | ||
| python3 "$API_SERVER" 2>/dev/null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The GUI_PORT variable is not passed to the API server, so the --port option is ignored. The API server will always run on its hardcoded port 8318.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/gui-cliproxyapi.sh, line 190:
<comment>The GUI_PORT variable is not passed to the API server, so the `--port` option is ignored. The API server will always run on its hardcoded port 8318.</comment>
<file context>
@@ -0,0 +1,203 @@
+if command -v python3 &> /dev/null; then
+ if [ -f "$API_SERVER" ]; then
+ # Use Python API server with management endpoints
+ python3 "$API_SERVER" 2>/dev/null
+ else
+ # Fallback to simple HTTP server
</file context>
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } | ||
| echo_success() { echo -e "${GREEN}[+] $1${NC}"; } | ||
| echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; } | ||
| echo_error() { echo -e "${RED}[-] $1${NC}"; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: Function echo_info is used but never defined. This will cause the script to fail at runtime with 'command not found'. Add the missing function definition alongside the other echo helper functions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/update-cliproxyapi.sh, line 38:
<comment>Function `echo_info` is used but never defined. This will cause the script to fail at runtime with 'command not found'. Add the missing function definition alongside the other echo helper functions.</comment>
<file context>
@@ -0,0 +1,234 @@
+echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; }
+echo_success() { echo -e "${GREEN}[+] $1${NC}"; }
+echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; }
+echo_error() { echo -e "${RED}[-] $1${NC}"; }
+
+echo -e "${MAGENTA}"
</file context>
| if gui_dir.exists(): | ||
| os.chdir(gui_dir) | ||
|
|
||
| with socketserver.TCPServer(("", PORT), APIHandler) as httpd: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Server binds to all network interfaces instead of localhost only. This exposes the management API to the entire network, allowing remote control of server start/stop, OAuth, and updates. For a local management API, bind to 127.0.0.1 instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/cliproxyapi-api-server.py, line 299:
<comment>Server binds to all network interfaces instead of localhost only. This exposes the management API to the entire network, allowing remote control of server start/stop, OAuth, and updates. For a local management API, bind to `127.0.0.1` instead.</comment>
<file context>
@@ -0,0 +1,309 @@
+ if gui_dir.exists():
+ os.chdir(gui_dir)
+
+ with socketserver.TCPServer(("", PORT), APIHandler) as httpd:
+ print(f"API Server running on http://localhost:{PORT}")
+ print(f"GUI available at http://localhost:{PORT}")
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive Linux and macOS support to CLIProxyAPIPlus-Easy-Installation, transforming it from a Windows-only toolkit into a truly cross-platform solution. The implementation includes six bash scripts for installation, server management, OAuth authentication, updates, GUI control, and uninstallation, along with a Python REST API backend for the GUI and updated documentation in both English and Indonesian.
Key Changes
- Bash installation and management scripts for Linux/macOS with auto-detection of OS and architecture, supporting both prebuilt binaries and source builds
- Python REST API server to power the GUI Control Center with 12+ management endpoints
- Comprehensive documentation updates including installation guides, testing instructions, and bash scripting conventions in AGENTS.md
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/install-cliproxyapi.sh |
Main installer with OS/architecture detection, binary installation, and configuration setup |
scripts/start-cliproxyapi.sh |
Server lifecycle manager with PID-based tracking and background/foreground modes |
scripts/update-cliproxyapi.sh |
Update script supporting prebuilt binaries and source builds with automatic server restart |
scripts/uninstall-cliproxyapi.sh |
Clean removal script with optional preservation of auth tokens |
scripts/gui-cliproxyapi.sh |
GUI launcher with browser auto-open and fallback to minimal HTML interface |
scripts/cliproxyapi-oauth.sh |
Interactive OAuth helper for 8 providers with batch login support |
scripts/cliproxyapi-api-server.py |
Python REST API backend providing management endpoints for the GUI |
scripts/AGENTS.md |
Enhanced documentation with bash patterns, conventions, and best practices |
README.md |
Added Linux/macOS quick start section with installation and testing instructions |
README_ID.md |
Indonesian translation of Linux/macOS documentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| MAGENTA='\033[0;35m' | ||
| NC='\033[0m' # No Color | ||
|
|
||
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent naming for output functions across bash scripts. This script defines echo_step() while all other scripts in this PR (start-cliproxyapi.sh, update-cliproxyapi.sh, cliproxyapi-oauth.sh, gui-cliproxyapi.sh, uninstall-cliproxyapi.sh) use echo_info() for informational output.
For consistency, rename echo_step() to echo_info() throughout this script. This will establish a consistent convention across all bash scripts.
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } | ||
| echo_success() { echo -e "${GREEN}[+] $1${NC}"; } | ||
| echo_warning() { echo -e "${YELLOW}[!] $1${NC}"; } | ||
| echo_error() { echo -e "${RED}[-] $1${NC}"; } |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing echo_info() function definition. The script calls echo_info() on lines 54, 60, 121, 122, 139, 159, 160, and 164, but only defines echo_step(), echo_success(), echo_warning(), and echo_error(). This will cause runtime errors when echo_info() is called.
Add the missing function definition:
echo_info() { echo -e "${CYAN}[*] $1${NC}"; }Alternatively, for consistency with most other scripts in this PR, you could use echo_info() everywhere and remove echo_step(), or standardize on one naming convention across all scripts.
| echo_error() { echo -e "${RED}[-] $1${NC}"; } | |
| echo_error() { echo -e "${RED}[-] $1${NC}"; } | |
| echo_info() { echo -e "${CYAN}[*] $1${NC}"; } |
| if command -v python3 &> /dev/null; then | ||
| if [ -f "$API_SERVER" ]; then | ||
| # Use Python API server with management endpoints | ||
| python3 "$API_SERVER" 2>/dev/null |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom port specified via --port flag is not passed to the Python API server. The cliproxyapi-api-server.py script has a hardcoded PORT = 8318 on line 15, so even if a user specifies --port 9000, the API server will still run on port 8318.
To fix this, pass the GUI_PORT as an argument or environment variable to the Python script:
GUI_PORT=$GUI_PORT python3 "$API_SERVER" 2>/dev/nullThen update the Python script to read from the environment:
PORT = int(os.environ.get('GUI_PORT', 8318))| python3 "$API_SERVER" 2>/dev/null | |
| GUI_PORT=$GUI_PORT python3 "$API_SERVER" 2>/dev/null |
| def handle_models(self): | ||
| """Get available models""" | ||
| try: | ||
| result = subprocess.run( | ||
| ["curl", "-s", "-H", "Authorization: Bearer sk-dummy", | ||
| "http://localhost:8317/v1/models"], | ||
| capture_output=True, | ||
| text=True, | ||
| timeout=5 | ||
| ) | ||
|
|
||
| if result.returncode == 0: | ||
| data = json.loads(result.stdout) | ||
| models = [m["id"] for m in data.get("data", [])] | ||
| self.send_json({"models": models}) | ||
| else: | ||
| self.send_json({"models": []}) | ||
| except Exception as e: | ||
| self.send_json({"models": [], "error": str(e)}) |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using curl via subprocess to make HTTP requests is inefficient and requires an external dependency. Python has built-in libraries for HTTP requests that would be more reliable and portable.
Consider using Python's urllib.request (built-in) or checking if requests is available:
import urllib.request
import urllib.error
def handle_models(self):
"""Get available models"""
try:
req = urllib.request.Request(
"http://localhost:8317/v1/models",
headers={"Authorization": "Bearer sk-dummy"}
)
with urllib.request.urlopen(req, timeout=5) as response:
data = json.loads(response.read())
models = [m["id"] for m in data.get("data", [])]
self.send_json({"models": models})
except Exception as e:
self.send_json({"models": [], "error": str(e)})| RED='\033[0;31m' | ||
| NC='\033[0m' # No Color | ||
|
|
||
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation shows echo_step() as the standard function name, but most bash scripts in this PR (start-cliproxyapi.sh, cliproxyapi-oauth.sh, gui-cliproxyapi.sh) use echo_info() instead. This inconsistency between documentation and implementation will confuse future contributors.
Update the documentation to reflect the actual convention used in most scripts:
echo_info() { echo -e "${CYAN}[*] $1${NC}"; }Or alternatively, standardize all scripts to use echo_step() if that's the preferred naming.
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } | |
| echo_info() { echo -e "\n${CYAN}[*] $1${NC}"; } |
| echo_info "Starting server in background..." | ||
| nohup "$BINARY_PATH" --config "$CONFIG_PATH" > "$LOG_FILE" 2>&1 & | ||
| PID=$! | ||
| echo $PID > "$PID_FILE" |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PID variable should be quoted when writing to the file for better shell script practices, although in this case it's unlikely to cause issues since PIDs don't contain spaces.
Change:
echo $PID > "$PID_FILE"To:
echo "$PID" > "$PID_FILE"| echo $PID > "$PID_FILE" | |
| echo "$PID" > "$PID_FILE" |
| # Remove Droid custom models | ||
| if [ -f "$FACTORY_DIR/config.json" ]; then | ||
| echo_step "Removing Droid custom models..." | ||
| rm -f "$FACTORY_DIR/config.json" | ||
| echo_success "Removed: $FACTORY_DIR/config.json" | ||
| fi |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The uninstall script completely removes ~/.factory/config.json when --all flag is used. This will delete all custom model configurations that users may have set up, not just CLIProxyAPI-Plus models. If users have configured other custom models in Factory Droid, those will be lost.
Consider either:
- Warning the user more explicitly that this will remove ALL custom models
- Attempting to remove only CLIProxyAPI-Plus entries from the config.json (using jq or similar)
- Creating a backup before deletion
At minimum, add a more explicit warning message before this deletion:
echo_warning "This will remove ALL Factory Droid custom models, not just CLIProxyAPI-Plus models"| MAGENTA='\033[0;35m' | ||
| NC='\033[0m' | ||
|
|
||
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent naming for output functions across bash scripts. The update-cliproxyapi.sh script uses both echo_step() (defined on line 35) and echo_info() (called on lines 61, 70, 113, etc.) without defining echo_info(). This will cause runtime errors when the undefined function is called.
For consistency with other scripts in this PR (start-cliproxyapi.sh, cliproxyapi-oauth.sh, gui-cliproxyapi.sh, uninstall-cliproxyapi.sh which all use echo_info()), rename echo_step() to echo_info() in this script.
| echo_step() { echo -e "\n${CYAN}[*] $1${NC}"; } | |
| echo_info() { echo -e "\n${CYAN}[*] $1${NC}"; } |
| import json | ||
| import subprocess | ||
| import os | ||
| from urllib.parse import urlparse, parse_qs |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'parse_qs' is not used.
| from urllib.parse import urlparse, parse_qs | |
| from urllib.parse import urlparse |
| if command -v python3 &> /dev/null; then | ||
| if [ -f "$API_SERVER" ]; then | ||
| # Use Python API server with management endpoints | ||
| python3 "$API_SERVER" 2>/dev/null | ||
| else | ||
| # Fallback to simple HTTP server | ||
| cd "$GUI_DIR" | ||
| python3 -m http.server "$GUI_PORT" 2>/dev/null |
Copilot
AI
Dec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gui-cliproxyapi.sh starts the Python management server (cliproxyapi-api-server) as a long-lived HTTP API without any authentication or CSRF protection, exposing sensitive operations like start/stop/restart and config access over HTTP on port 8318. Because the backend binds to all interfaces and sets permissive CORS, any process on the local network or any web page running in the user’s browser can issue cross-origin requests to control the proxy and read configuration data. Restrict the management server to 127.0.0.1, add a per-user auth token checked on each request, and narrow CORS to the local GUI origin instead of * before starting it here.
| if command -v python3 &> /dev/null; then | |
| if [ -f "$API_SERVER" ]; then | |
| # Use Python API server with management endpoints | |
| python3 "$API_SERVER" 2>/dev/null | |
| else | |
| # Fallback to simple HTTP server | |
| cd "$GUI_DIR" | |
| python3 -m http.server "$GUI_PORT" 2>/dev/null | |
| # Generate a random per-user auth token | |
| AUTH_TOKEN="$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 32)" | |
| CORS_ORIGIN="http://localhost:$GUI_PORT" | |
| if command -v python3 &> /dev/null; then | |
| if [ -f "$API_SERVER" ]; then | |
| # Use Python API server with management endpoints | |
| python3 "$API_SERVER" \ | |
| --host 127.0.0.1 \ | |
| --port "$GUI_PORT" \ | |
| --auth-token "$AUTH_TOKEN" \ | |
| --cors-origin "$CORS_ORIGIN" \ | |
| 2>/dev/null | |
| else | |
| # Fallback to simple HTTP server | |
| cd "$GUI_DIR" | |
| python3 -m http.server "$GUI_PORT" --bind 127.0.0.1 2>/dev/null |
🎯 Overview
This PR adds full Linux and macOS support to CLIProxyAPIPlus-Easy-Installation, making it a truly cross-platform installation toolkit.
✨ What's New
🐧 Linux/macOS Installation Scripts
install-cliproxyapi.sh(389 lines) - Main installer with OS/architecture auto-detectionstart-cliproxyapi.sh(207 lines) - Server lifecycle manager with background/foreground modescliproxyapi-oauth.sh(252 lines) - Interactive OAuth login for 8 providersupdate-cliproxyapi.sh(234 lines) - Update from prebuilt binaries or sourceuninstall-cliproxyapi.sh(164 lines) - Clean removal with optional auth preservationgui-cliproxyapi.sh(203 lines) - GUI launcher with browser auto-open🖥️ GUI Control Center for Linux
cliproxyapi-api-server.py(309 lines) - Python REST API backend for GUI managementgui/index.html(603 lines added) - Enhanced with API integration/api/status,/api/start,/api/stop,/api/oauth/{provider}, etc.📚 Documentation
README.mdandREADME_ID.mdwith Linux/macOS installation sectionsscripts/AGENTS.mdwith bash patterns and conventions (+177 lines)🔧 Technical Details
Installation Features
cli-proxy-api-plusandcliproxyapi-plus~/.local/binwith proper PATH configuration~/.local/share/cliproxyapi/gui/Server Management
~/.cli-proxy-api/server.pid)nohupand log rotationGUI Features
xdg-openoropencommand🧪 Testing
Tested on Ubuntu 22.04: